package battleship;
import java.util.Random;

/**
 * This class peforms all of the AI decision for the game.
 * @author Code: Ammar Ahmed, Katelyn Doran, Shaun Pickford
 *         Psuedocode: Rob Brown, Mike Colmer, Darren Harton
 * date april 14
 * ver 0.02
 */
public class AI
{

    /* Objects for referencing Other Classes */
    Conversion conversionObj = new Conversion();

    /* Boolean Variables needed for patterns */
    boolean ACPatternComplete = false;
    boolean BSPatternComplete = false;
    boolean EEPatternComplete = false;
    boolean inShipHitPattern = false;
    boolean setFirstHit = true;

    /* Values for Aircraft Carrier Pattern */
    int[] aircraftCarrierPatternArray = {1,12,23,34,45,56,67,78,89,100,6,17,28,39,50};

    /* Values for Battleship Pattern */
    int[] battleshipPatternArray = {2,13,24,35,46,57,68,79,90,41,52,63,10,91};

    /* Values for Everything Else Pattern */
    int[] everythingElsePatternArray = {4,15,26,37,48,59,70,8,19,30,21,32,43,54,65,76,87,98,71,82,93};

    /* Pattern index variables */
    int ACPatternNextIndex =0; //Aircraft carrier
    int BSPatternNextIndex =0;  //battleship
    int EEPatternNextIndex =0; //everything else

    int shotsAfterHit[] = new int[5];        //keep list of blocks to visit.
    int shotsAfterHitNext = 0; //keeps track of the index

    Random rand = new Random(); //for random numbers

    /* Variables for shotAfterHit method (cannot be declared in method
     * because they will be overwritten
     * every time the method is called...
     */
    int[] nextShot = new int[4];
    boolean[] triedShot = new boolean[4];
    boolean determiningDirection = true;
    //int shotAfterHitIndex = Main.shotAfterHitIndex2;
    char shootingDirection;
    int firstHit = 0;

    int[] endPoints = new int[4];
    String[] directions = new String[4];

    /*Variables for checkDirections method */
    //create endpoint varialbes and booleans to indicate directions
    int upEndPoint, downEndPoint, leftEndPoint, rightEndPoint;
    boolean canGoUp, canGoDown, canGoLeft, canGoRight;
    int patternIndex = 0;


    /**No Args Constructor
     * 
     */
    public AI()
    {
        shuffleArray (aircraftCarrierPatternArray); //shuffle all the location so the AI wouldnt search in order.
        shuffleArray (battleshipPatternArray);
        shuffleArray (everythingElsePatternArray);
            //total number of blocks in all patterns = 58 out of 100

        ACPatternComplete = false;
        BSPatternComplete = false;
        EEPatternComplete = false;

    }

    /* This method runs EVERY TIME the opponent takes a shot */
    public int takeShot()
    {
        int shot;

        //if the previous shot taken was a hit AND SINK...set inShipHitPattern to true and reset values
        if(Main.gameBoard.opponentPreviousShotResult.equals("Hit and sink"))
        {
            inShipHitPattern = false;
            determiningDirection = true;
            Main.shotAfterHitIndex2 = 0;
            //shotAfterHitIndex = Main.shotAfterHitIndex2;
            setFirstHit = true;
        }

        //if the previous shot is a hit
        if(Main.gameBoard.opponentPreviousShotResult.equals("Hit"))
        {
            inShipHitPattern = true;
            if(setFirstHit)
            {
                Main.firstHit = Main.gameBoard.opponentPreviousShot;
                firstHit = Main.firstHit;
                setFirstHit = false;
            }
        }

        if (inShipHitPattern)
        {
            shot = shotAfterHit();
        }
        else if (!ACPatternComplete)
        {
            shot = ACPattern();
        }
        else if(!BSPatternComplete)
        {
            shot = BSPattern();
        }
        else if(!EEPatternComplete)
        {
            shot = EEPattern();
        }
        else
        {
            shot = randomShot();
        }

        return shot;
    }

    /** Shuffle array
     * This method gets an array and shuffle it's values
     * Used in: could be
     * @param array
     */
    private void shuffleArray(int[] array)
    {
        for(int i = 0; i < array.length; i++)
        {
            //finding a random index
            int swapLocation = rand.nextInt(array.length);
            //swapping the 2 values
            int temp = array[i];
            array[i] = array[swapLocation];
            array[swapLocation] = temp;
        }
    }


    /**ACNext
     * return the next value on the pattern
     * if there are no more values in the array then it would return -1
     */
    private int ACPattern()
    {
        if(Main.gameBoard.opponentPreviousShotResult.equals("tryAgain"))
        {
            ACPatternNextIndex++;
        }
        if( ACPatternNextIndex >= aircraftCarrierPatternArray.length )
        {
            ACPatternComplete = true;
            return BSPattern();
            //return -1; //value means that the array stepping is done
        }
        int returnedValue = aircraftCarrierPatternArray[ACPatternNextIndex];
        ACPatternNextIndex++;
        return returnedValue;
    }

    /**Battle ship next value
     * returns next value on the battleship array. If not then it returns -1
     */
    private int BSPattern()
    {
        if(Main.gameBoard.opponentPreviousShotResult.equals("tryAgain"))
        {
            BSPatternNextIndex++;
        }
        if( BSPatternNextIndex >= battleshipPatternArray.length  )
        {
            BSPatternComplete = true;
            return EEPattern();
            //return -1; //value means that the array stepping is done
        }
        int returnedValue = battleshipPatternArray[BSPatternNextIndex];
        BSPatternNextIndex++;
        return returnedValue;
    }

    /**everything else next value
     * returns the next value on the array. if the array is empty then it returns a -1
     */
    private int EEPattern()
    {
        if(Main.gameBoard.opponentPreviousShotResult.equals("tryAgain"))
        {
            EEPatternNextIndex++;
        }
        if( EEPatternNextIndex >= everythingElsePatternArray.length)
        {
            EEPatternComplete = true;
            return randomShot();
            //return -1;
        }
        int returnedValue = everythingElsePatternArray[EEPatternNextIndex];
        EEPatternNextIndex++;
        return returnedValue;
    }

    /**method returns a random value for the shot
     * ammar
     * @return
     */
    private int randomShot()
    {
        if(Main.gameBoard.opponentPreviousShotResult.equals("tryAgain"))
        {
            int returnedValue = rand.nextInt(100);
            returnedValue = returnedValue + 1;
        }
        
        int returnedValue = rand.nextInt(100);
        returnedValue = returnedValue + 1;
        return returnedValue;
    }

    public int shotAfterHit()
    {
        int shot = 0;

        //run the calculations to get all possible next shots based on firstHit received
        checkDirections(firstHit);

        //get array of possible next shots
        nextShot = getPossibleShots();

        //if all directions have been exhausted, reset all values and exit pattern
        if(nextShot[0] == -1 && nextShot[1] == -1 && nextShot[2] == -1 && nextShot[3] == -1)
        {
            determiningDirection = true;
            inShipHitPattern = false;
            Main.shotAfterHitIndex2 = 0;
            setFirstHit = true;
            shot = takeShot();
            patternIndex = 0;
            //return shot;
        }

        //if last shot was a miss
        if(Main.gameBoard.opponentPreviousShotResult.equals("Miss"))
        {
            //if there are still valid directions, change direction
            if(patternIndex < 3)
            {
                patternIndex++;
                shot = nextShot[patternIndex];
                //return shot;
            }
            else
            {
                determiningDirection = true;
                inShipHitPattern = false;
                Main.shotAfterHitIndex2 = 0;
                setFirstHit = true;
                shot = takeShot();
                patternIndex = 0;
                //return shot;
            }
        }//if last shot was a miss

        //if the direction you are trying to shoot in is no longer valid
        if(nextShot[patternIndex] == -1)
        {
            //if there are still valid directions, change direction
            if(patternIndex < 3)
            {
                patternIndex++;
                shot = nextShot[patternIndex];
                //return shot;
            }
            else
            {
                determiningDirection = true;
                inShipHitPattern = false;
                Main.shotAfterHitIndex2 = 0;
                setFirstHit = true;
                shot = takeShot();
                patternIndex = 0;
                //return shot;
            }
            
        }//if the direction you are trying to shoot in is no longer valid

        else
        {
            shot = nextShot[patternIndex];
            //return shot;
        }

        return shot;
    }//shotAfterHit()

    public void checkDirections(int startCoordinate)
    {

        /* Clear arrays */
        for(int xx = 0; xx < endPoints.length; xx++)
        {
            endPoints[xx] = -1;
            directions[xx] = "";

        }

        /* Calculate endpoints based on starting coordinate */
        upEndPoint = startCoordinate - 10;
        downEndPoint = startCoordinate + 10;
        leftEndPoint = startCoordinate - 1;
        rightEndPoint = startCoordinate + 1;
        //System.out.println("upendPoint: " + upEndPoint + " downEndPoint: " + downEndPoint + " leftEndPoint: " + leftEndPoint + " rightEndPoint: " + rightEndPoint);

        /* Determine if endpoints are valid */
        canGoUp = validateShots("U", upEndPoint, startCoordinate);
        canGoDown = validateShots("D", downEndPoint, startCoordinate);
        canGoLeft = validateShots("L", leftEndPoint, startCoordinate);
        canGoRight = validateShots("R", rightEndPoint, startCoordinate);

        /* If up endPoint is valid */
        if(canGoUp)
        {
            endPoints[0] = upEndPoint;
            directions[0] = "U";
            //System.out.println("can go up!");
        }//can go up

        /* If down endPoint is valid */
        if(canGoDown)
        {
            endPoints[1] = downEndPoint;
            directions[1] = "D";
            //System.out.println("can go down!");

        }//can go down

        /* If left endPoint is valid */
        if(canGoLeft)
        {
            endPoints[2] = leftEndPoint;
            directions[2] = "L";
            //System.out.println("can go left!");
        }//can go left

        /* If right endPoint is valid */
        if(canGoRight)
        {
            endPoints[3] = rightEndPoint;
            directions[3] = "R";
            //System.out.println("can go right!");
        }//can go right

    }

    private boolean validateShots(String direction, int nextShot, int previousShot)
    {
        boolean valid = true;

        /* Check to see if endpoint is on the board. */
        if(nextShot < 1  || nextShot > 100)
        {
            valid = false;
            //System.out.println("Endpoint is off the board!");
        }

        /* Check to see if endpoint is on the same row if a horizontal endPoint is being determined */
        if(direction.equalsIgnoreCase("L") || direction.equalsIgnoreCase("R"))
        {
            String startCoordinate = conversionObj.toCoordinate(previousShot);
            //System.out.println("startCoordiante is " + startCoordinate);
            String endCoordinate = conversionObj.toCoordinate(nextShot);
            //System.out.println("endCoordiante is " + endCoordinate);
            String temp1 = startCoordinate.substring(0,1);
            if(!endCoordinate.equals("error"))
            {
                String temp2 = endCoordinate.substring(0,1);
                if(temp1.equals(temp2))
                {
                    valid = true;
                    //System.out.println("start and end coordinates are on the same row!");
                }
                else
                {
                    valid = false;
                }

            }//if endCoordinate is a valid coordiante

        }//if horizontal check for same row

        /*Check to see if startingPoint is in the far left column...if so, the left endpoint is invalid */
        if(direction.equalsIgnoreCase("L"))
        {
            //bool to test if this shot has been taken already, assume it has
            boolean hasBeenTried = true;

            //while the shot being looked at has already been taken
            while(hasBeenTried)
            {
                //check if the previous shot is in the far left column...if so, any leftward shot is invalid... mark it as so
                if (previousShot % 10 == 1)
                {
                    valid = false;
                    break;
                }

                //if the shot has been used already
                if(Main.gameBoard.opponentShotRecord[nextShot - 1])
                {
                    //if shot you are checking is in far left column, break out of loop...you cannot go left anymore
                    if(nextShot % 10 == 1)
                     {
                         valid = false;
                         break;
                     }
                    else
                    {
                        nextShot = nextShot - 1;
                    }
                }
                else
                {
                    hasBeenTried = false;
                    valid = true;
                    leftEndPoint = nextShot;
                }
                
            }//while shot has been tried
        }

        /*Check to see if startingPoint is in far right column...if so, the right endpoint is invalid */
        else if(direction.equalsIgnoreCase("R"))
        {
            //bool to test if this shot has been taken already, assume it has
            boolean hasBeenTried = true;

            //while the shot being looked at has already been taken
            while(hasBeenTried)
            {
                //check if the previous shot is in the far right column...if so, any right shot is invalid... mark it as so
                if (previousShot % 10 == 0)
                {
                    valid = false;
                    break;
                }

                //if the shot has been used already
                if(Main.gameBoard.opponentShotRecord[nextShot - 1])
                {
                    //if shot you are checking is in far right column, break out of loop...you cannot go right anymore
                    if(nextShot % 10 == 0)
                     {
                         valid = false;
                         break;
                     }
                    else
                    {
                        nextShot = nextShot + 1;
                    }
                }
                else
                {
                    hasBeenTried = false;
                    valid = true;
                    rightEndPoint = nextShot;
                }

            }//while shot has been tried
        }

        /*Check to see if startingPoint is on top row...if so, the up endpoint is inva;lid */
        else if(direction.equalsIgnoreCase("U"))
        {
            //bool to test if this shot has been taken already, assume it has
            boolean hasBeenTried = true;

            //while the shot being looked at has already been taken
            while(hasBeenTried)
            {
                //check if the previous shot is in the top row...if so, any upward shot is invalid... mark it as so
                if (previousShot < 11)
                {
                    valid = false;
                    break;
                }

                //if the shot has been used already
                if(Main.gameBoard.opponentShotRecord[nextShot - 1])
                {
                    //if shot you are checking is in top row, break out of loop...you cannot go up anymore
                    if(nextShot < 11)
                     {
                         valid = false;
                         break;
                     }
                    else
                    {
                        nextShot = nextShot - 10;
                    }
                }
                else
                {
                    hasBeenTried = false;
                    valid = true;
                    upEndPoint = nextShot;
                }

            }//while shot has been tried
        }

        /*Check to see if startingPoint is on bottom row...if so, the down endpoint is invalid */
        else if(direction.equalsIgnoreCase("D"))
        {
            //bool to test if this shot has been taken already, assume it has
            boolean hasBeenTried = true;

            //while the shot being looked at has already been taken
            while(hasBeenTried)
            {
                //check if the previous shot is in the top row...if so, any upward shot is invalid... mark it as so
                if (previousShot > 90)
                {
                    valid = false;
                    break;
                }

                //if the shot has been used already
                if(Main.gameBoard.opponentShotRecord[nextShot - 1])
                {
                    //if shot you are checking is in far right column, break out of loop...you cannot go left anymore
                    if(nextShot > 90)
                     {
                         valid = false;
                         break;
                     }
                    else
                    {
                        nextShot = nextShot + 10;
                    }
                }
                else
                {
                    hasBeenTried = false;
                    valid = true;
                    downEndPoint = nextShot;
                }

            }//while shot has been tried
        }

        return valid;

    }//validate end points

    public String[] getPossibleDirections()
    {
        return directions;
    }

    public int[] getPossibleShots()
    {
        return endPoints;
    }


}//class
